package com.yy.wga.admin.service.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.yy.wga.common.core.exception.BusinessException;
import com.yy.wga.mp.common.dto.UserCacheDTO;
import com.yy.wga.mp.common.interceptor.RequestUserHolder;
import com.yy.wga.mp.common.utils.common.IdUtils;
import com.yy.wga.mp.common.utils.common.StringUtils;
import com.yy.wga.mp.common.utils.mapping.BeansUtils;
import com.yy.wga.mp.common.utils.sign.Md5Utils;
import com.yy.wga.admin.service.pojo.AdminMenuDO;
import com.yy.wga.admin.service.pojo.AdminRoleDO;
import com.yy.wga.admin.service.pojo.AdminRoleMenuDO;
import com.yy.wga.admin.service.pojo.AdminUserDO;
import com.yy.wga.admin.service.pojo.AdminUserRoleDO;
import com.yy.wga.mp.module.admin.mapper.AdminUserMapper;
import com.yy.wga.mp.module.admin.request.AdminUserIoginRequest;
import com.yy.wga.mp.module.admin.request.AdminUserPageRequest;
import com.yy.wga.mp.module.admin.request.AdminUserSaveRequest;
import com.yy.wga.mp.module.admin.request.AdminUserUpdateStatusRequest;
import com.yy.wga.mp.module.admin.response.AdminMenuInfoResponse;
import com.yy.wga.mp.module.admin.response.AdminUserInfoResponse;
import com.yy.wga.mp.module.admin.response.AdminUserPageResponse;
import com.yy.wga.mp.module.admin.service.AdminMenuService;
import com.yy.wga.mp.module.admin.service.AdminRoleMenuService;
import com.yy.wga.mp.module.admin.service.AdminRoleService;
import com.yy.wga.mp.module.admin.service.AdminUserRoleService;
import com.yy.wga.mp.module.admin.service.AdminUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 用户信息(AdminUser)表服务实现类
 *
 * @author guochao
 * @since 2022-11-01 19:08:37
 */
@Service
@RequiredArgsConstructor
public class AdminUserServiceImpl extends ServiceImpl<AdminUserMapper, AdminUserDO> implements AdminUserService {

    private final StringRedisTemplate stringRedisTemplate;
    private final AdminUserRoleService userRoleService;
    private final AdminRoleService roleService;
    private final AdminRoleMenuService roleMenuService;
    private final AdminMenuService menuService;

    @Override
    public AdminUserInfoResponse login(AdminUserIoginRequest request) {
        AdminUserDO adminUserDO = baseMapper.selectOne(new LambdaQueryWrapper<AdminUserDO>()
                .eq(AdminUserDO::getPhone, request.getMobile()));
        if (adminUserDO == null || adminUserDO.getStatus().equals(2)) {
            throw new BusinessException("手机号不存在");
        }
        if (adminUserDO.getStatus().equals(0)) {
            throw new BusinessException("用户已禁用");
        }
        String salt = adminUserDO.getSalt();
        String saltPwd = Md5Utils.saltPassword(request.getPassword(), salt);
        if (!saltPwd.equals(adminUserDO.getPassword())) {
            throw new BusinessException("密码错误");
        }
        // 查询角色
        List<AdminUserRoleDO> userRoleList = userRoleService.list(new LambdaQueryWrapper<AdminUserRoleDO>()
                .eq(AdminUserRoleDO::getAppKey, RequestUserHolder.getBaseRequest().getAppKey())
                .eq(AdminUserRoleDO::getUserId, adminUserDO.getId()));
        if (CollectionUtils.isEmpty(userRoleList)) {
            throw new BusinessException("用户无权限");
        }
        Set<Long> roleIds = userRoleList.stream()
                .map(AdminUserRoleDO::getRoleId).collect(Collectors.toSet());
        List<AdminRoleDO> roleList = roleService.list(new LambdaQueryWrapper<AdminRoleDO>()
                .eq(AdminRoleDO::getAppKey, RequestUserHolder.getBaseRequest().getAppKey())
                .in(AdminRoleDO::getStatus, 1)
                .in(AdminRoleDO::getId, roleIds));
        if (CollectionUtils.isEmpty(roleList)) {
            throw new BusinessException("用户无权限");
        }
        List<AdminUserInfoResponse.RoleInfo> roleInfos = BeansUtils.mapList(roleList, AdminUserInfoResponse.RoleInfo.class);
        // 查询菜单
        List<AdminMenuDO> menuList;
        if (roleIds.contains(20241101L)) {
            // 超管可以查看全部菜单
            menuList = menuService.list(new LambdaQueryWrapper<AdminMenuDO>()
                    .eq(AdminMenuDO::getAppKey, RequestUserHolder.getBaseRequest().getAppKey()));
        } else {
            List<AdminRoleMenuDO> roleMenuList = roleMenuService.list(new LambdaQueryWrapper<AdminRoleMenuDO>()
                    .eq(AdminRoleMenuDO::getAppKey, RequestUserHolder.getBaseRequest().getAppKey())
                    .in(AdminRoleMenuDO::getRoleId, roleIds));
            if (CollectionUtils.isEmpty(userRoleList)) {
                throw new BusinessException("用户角色无权限");
            }
            menuList = menuService.list(new LambdaQueryWrapper<AdminMenuDO>()
                    .eq(AdminMenuDO::getAppKey, RequestUserHolder.getBaseRequest().getAppKey())
                    .in(AdminMenuDO::getId, roleMenuList.stream()
                            .map(AdminRoleMenuDO::getMenuId).collect(Collectors.toSet())));
        }
        menuList.sort(Comparator.comparing(AdminMenuDO::getSort).reversed());
        List<AdminMenuInfoResponse> menuInfos = BeansUtils.mapList(menuList, AdminMenuInfoResponse.class);
        menuInfos = menuService.getMenuTree(menuInfos, 0L);

        // 缓存
        String token = IdUtils.uuid();
        UserCacheDTO adminUserCacheDTO = new UserCacheDTO();
        adminUserCacheDTO.setUserId(adminUserDO.getId());
        adminUserCacheDTO.setToken(token);
        adminUserCacheDTO.setPhone(adminUserDO.getPhone());
        adminUserCacheDTO.setUserName(adminUserDO.getUsername());
        String redisKey = GlobalConstant.USER_INFO + token;
        stringRedisTemplate.opsForValue().set(redisKey, JSON.toJSONString(adminUserCacheDTO), 6, TimeUnit.HOURS);

        AdminUserInfoResponse response = new AdminUserInfoResponse();
        response.setMobile(adminUserDO.getPhone());
        response.setToken(token);
        response.setRoleInfos(roleInfos);
        response.setMenuInfos(menuInfos);
        response.setUsername(adminUserDO.getUsername());
        return response;
    }

    @Override
    public void logout() {
        String adminUserInfoKey = GlobalConstant.USER_INFO + RequestUserHolder.getUserCache().getToken();
        stringRedisTemplate.delete(adminUserInfoKey);
    }

    @Override
    public PageBean<AdminUserPageResponse> pageData(AdminUserPageRequest request) {
        LambdaQueryWrapper<AdminUserDO> queryWrapper = new LambdaQueryWrapper<AdminUserDO>()
                .eq(AdminUserDO::getAppKey, RequestUserHolder.getBaseRequest().getAppKey())
                .eq(StringUtils.isNotBlank(request.getPhone()), AdminUserDO::getPhone, request.getPhone())
                .eq(request.getStatus() != null, AdminUserDO::getStatus, request.getStatus());
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<AdminUserDO> adminUserList = baseMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(adminUserList)) {
            PageBean<AdminUserPageResponse> pageBean = new PageBean<>();
            pageBean.setPageNum(request.getPageNum());
            pageBean.setPageSize(request.getPageSize());
            return pageBean;
        }

        // 查询角色id和角色名
        List<AdminUserRoleDO> userRoleList = userRoleService.list(new LambdaQueryWrapper<AdminUserRoleDO>()
                .eq(AdminUserRoleDO::getAppKey, RequestUserHolder.getBaseRequest().getAppKey())
                .in(AdminUserRoleDO::getUserId, adminUserList.stream()
                        .map(AdminUserDO::getId).collect(Collectors.toSet())));
        Map<Long, AdminUserRoleDO> userRoleMap = userRoleList.stream()
                .collect(Collectors.toMap(AdminUserRoleDO::getUserId, Function.identity()));
        List<AdminRoleDO> roleList = roleService.listByIds(userRoleList.stream()
                .map(AdminUserRoleDO::getRoleId).collect(Collectors.toSet()));
        Map<Long, String> roleMap = roleList.stream().collect(Collectors.toMap(AdminRoleDO::getId, AdminRoleDO::getName));

        // 填充数据
        List<AdminUserPageResponse> responseList = BeansUtils.mapList(adminUserList, AdminUserPageResponse.class);
        for (AdminUserPageResponse response : responseList) {
            AdminUserRoleDO adminUserRole = userRoleMap.get(response.getId());
            if (adminUserRole == null) {
                continue;
            }
            String roleName = roleMap.get(adminUserRole.getRoleId());
            response.setRoleId(adminUserRole.getRoleId());
            response.setRoleName(roleName);
        }
        PageBean<AdminUserPageResponse> pageBean = new PageBean<>();
        pageBean.setPageInfo(adminUserList);
        pageBean.setList(responseList);
        return pageBean;
    }

    @Override
    public void updateStatus(AdminUserUpdateStatusRequest request) {
        this.update(new LambdaUpdateWrapper<AdminUserDO>()
                .eq(AdminUserDO::getAppKey, RequestUserHolder.getBaseRequest().getAppKey())
                .eq(AdminUserDO::getId, request.getId())
                .set(AdminUserDO::getStatus, request.getStatus()));
    }

    @Override
    @Transactional
    public void saveUser(AdminUserSaveRequest request) {
        if (request.getId() != null) {
            AdminUserDO adminUserDO = baseMapper.selectById(request.getId());
            if (adminUserDO == null) {
                throw new BusinessException("用户不存在");
            }
            AdminUserDO update = BeansUtils.map(request, AdminUserDO.class);
            String saltPwd = Md5Utils.saltPassword(request.getPassword(), adminUserDO.getSalt());
            update.setPassword(saltPwd);
            update.setId(request.getId());
            baseMapper.updateById(update);

            userRoleService.update(new LambdaUpdateWrapper<AdminUserRoleDO>()
                    .eq(AdminUserRoleDO::getAppKey, RequestUserHolder.getBaseRequest().getAppKey())
                    .eq(AdminUserRoleDO::getUserId, request.getId())
                    .set(AdminUserRoleDO::getRoleId, request.getRoleId()));
        } else {
            AdminUserDO adminUserDO = BeansUtils.map(request, AdminUserDO.class);
            adminUserDO.setAppKey(RequestUserHolder.getBaseRequest().getAppKey());
            String salt = IdUtils.genRandomString(10);
            String saltPwd = Md5Utils.saltPassword(request.getPassword(), salt);
            adminUserDO.setSalt(salt);
            adminUserDO.setPassword(saltPwd);
            adminUserDO.setId(request.getId());
            baseMapper.insert(adminUserDO);

            AdminUserRoleDO adminUserRoleDO = new AdminUserRoleDO();
            adminUserRoleDO.setAppKey(RequestUserHolder.getBaseRequest().getAppKey());
            adminUserRoleDO.setUserId(adminUserDO.getId());
            adminUserRoleDO.setRoleId(request.getRoleId());
            userRoleService.save(adminUserRoleDO);
        }
    }

    @Override
    @Transactional
    public void delUser(Long id) {
        baseMapper.deleteById(id);

        userRoleService.remove(new LambdaUpdateWrapper<AdminUserRoleDO>()
                .eq(AdminUserRoleDO::getAppKey, RequestUserHolder.getBaseRequest().getAppKey())
                .eq(AdminUserRoleDO::getUserId, id));
    }
}
